import { Component, OnDestroy, OnInit, ViewChild, EventEmitter } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { merge, of as observableOf } from 'rxjs';
import { catchError, map, startWith, switchMap } from 'rxjs/operators';
// import { SelectionModel } from '@angular/cdk/collections';
// import { MatTableDataSource } from '@angular/material';
import { Router } from '@angular/router';
import { MatDialog, MatMenuTrigger } from '@angular/material';
import { RestService } from '../services/rest.service';
import { TranslateService } from '@ngx-translate/core';
import { InstitutionDialogComponent } from './institution-dialog/institution-dialog.component';
import { InstPasswordDialogComponent } from './inst-password-dialog/inst-password-dialog.component';
import { DialogTypes, ActionTypes } from '../models/wdl-types';

import * as _ from 'lodash';

const USERID = 'USERID=';

@Component({
  templateUrl: './institution.component.html',
  styleUrls: ['./institution.component.css'],
})
export class InstitutionComponent implements OnInit, OnDestroy {
  // displayedColumns: string[] = ['select', 'instName', 'description', 'actions'];
  // dataSource = new MatTableDataSource<any>([]);
  // selection = new SelectionModel<any>(true, []);
  url = 'data/institution';
  userUrl = 'api/keycloak/user';
  institutionUrl = 'api/keycloak/institution';
  displayedColumns: string[] = ['number', 'instName', 'ip', 'username', 'actions'];
  dataSource = [];
  searchText = '';

  resultsLength = 0;
  pageSize = 25;
  isLoadingResults = true;

  search: EventEmitter<any> = new EventEmitter();

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  constructor(public dialog: MatDialog,
              private router: Router,
              private translate: TranslateService,
              private rest: RestService) {
  }

  navigateTo(item) {
    this.router.navigateByUrl('/institution/' + item);
  }

  refreshSearch() {
    this.paginator.pageIndex = 0;
    this.search.emit(this.searchText);
  }

  add() {
    this.dialog.open(InstitutionDialogComponent, {
      disableClose: false,
      autoFocus: false,
      width: '450px',
      data: {
        mode: ActionTypes.ADD
      }
    }).afterClosed().subscribe(data => {
      if (!data || _.isString(data)) {
        // action was aborted
        return;
      }

      // add user
      this.rest.post(this.userUrl, {
        username: data.username,
        password: data.password,
        firstName: data.instName,
        enabled: true,
        role: 'admin'
      }).subscribe(resp => {
        let userId = resp['info'];
        if (userId && userId.startsWith(USERID)) {
          console.log('User ' + data.username + ' was added, ' + userId);
          userId = userId.substring(USERID.length);

          // add inst
          data['userid'] = userId;

          // check if institution is for 护适通
          if (data.instName === '护适通') {
            data.ip = '';
          }

          this.rest.post(this.url, data).subscribe(() => {
            this.refreshSearch();
          }, message => {
            this.rest.showHttpError('addInstError', message);
            this.refreshSearch();
          });
        } else {
          this.showAddUserError(data, resp);
          // try to remove the user
          const userIdIndex = userId.indexOf(USERID);
          if (userIdIndex > -1) {
            userId = userId.subscribe(userIdIndex + USERID.length);
            this.rest.delete(this.userUrl + '/' + userId).subscribe(() => {
              console.log('User ' + userId + ' was removed!');
            });
          }
        }
      }, (resp) => {
        this.showAddUserError(data, resp);
      });
    });
  }

  showAddUserError(data, resp) {
    console.error('User ' + data.username + ' was NOT added: ' + JSON.stringify(resp));
    const title = this.translate.get('addInstError')['value'];
    const message = this.translate.get('addUserError')['value'];
    this.rest.openGenDialog(DialogTypes.ERROR, title, message, null);
  }

  modify(item) {
    this.dialog.open(InstitutionDialogComponent, {
      disableClose: false,
      autoFocus: false,
      width: '450px',
      data: {
        mode: ActionTypes.MODIFY,
        item: item
      }
    }).afterClosed().subscribe(data => {
      if (!data || _.isString(data)) {
        // action was aborted
        return;
      }

      this.rest.put(this.institutionUrl, {
        oldInst: item.instName,
        newInst: data.instName
      }).subscribe(resp => {
        // add user info back
        data['username'] = item.username;
        data['userid'] = item.userid;

        // check if institution is for 护适通
        if (data.instName === '护适通') {
          data.ip = '';
        }

        this.rest.put(this.url + '/' + item.id, data).subscribe(response => {
          this.refreshSearch();
        }, message => {
          this.rest.showHttpError('modifyInstError', message);
        });
      }, () => {
        console.error('Failed to update user for institution ' + data.instName);
      });
    });
  }

  checkChild(institution, succ, fail) {
    this.rest.get(this.url + '/' + institution.id + '/buildings').subscribe(data => {
      const children = data['_embedded']['buildings'];
      if (children && children.length > 0) {
        if (fail) {
          fail();
        }
      } else {
        if (succ) {
          succ();
        }
      }
    }, () => {
      if (fail) {
        fail();
      }
    });
  }

  remove (institution) {
    this.checkChild(institution, () => {
      this.doRemove(institution);
    }, () => {
      const nonEmptyTitle = this.translate.get('deleteError')['value'];
      const nonEmptyMessage = this.translate.get('nonEmptyInstitution')['value'];
      this.rest.openGenDialog(DialogTypes.ERROR, nonEmptyTitle, nonEmptyMessage, null);
      return;
    });
  }

  doRemove(institution) {
    const title = this.translate.get('deleteConfirmation')['value'];
    const message = this.translate.get('deleteInstMessage', {instName: institution.instName})['value'];

    this.rest.openGenDialog(DialogTypes.CONFIRMATION, title, message, () => {
      /*
      this.rest.delete(this.userUrl + '/' + institution.userid).subscribe(() => {
        console.log('User ' + institution.username + ' was removed.');
      }, () => {
        console.error('User ' + institution.username + ' was NOT removed.');
      });
      */
      this.rest.post(this.institutionUrl + '/remove', {
        instName: institution.instName
      }).subscribe(() => {
        console.log('Users under ' + institution.instName + ' was removed.');
      }, () => {
        console.log('Users under ' + institution.instName + ' was NOT removed.');
      });

      this.rest.delete(this.url + '/' + institution.id).subscribe(() => {
        this.refreshSearch();
      }, error => {
        this.rest.showHttpError(this.translate.get('error')['value'], error);
      });
    });
  }

  changePassword(inst) {
    this.dialog.open(InstPasswordDialogComponent, {
      disableClose: false,
      autoFocus: false,
      width: '450px',
      data: {
        item: inst
      }
    }).afterClosed().subscribe(data => {
      if (!data || _.isString(data)) {
        // action was aborted
        return;
      }

      this.rest.put(this.userUrl + '/' + inst.userid + '/reset-password', data).subscribe(() => {
      }, message => {
        this.rest.showHttpError('resetPasswordError', message);
      });
    });
  }

  /*
  removeAll() {
    const title = this.translate.get('deleteConfirmation')['value'];
    const message = this.translate.get('deleteAllMessage')['value'];

    const urls = [];
    this.dataSource.forEach(item => {
      urls.push(this.url + '/' + item.id);
    });

    this.rest.openGenDialog(DialogTypes.CONFIRMATION, title, message, () => {
      this.rest.deleteAll(urls).subscribe(result => {
        this.refreshSearch();
      }, message => {
        this.rest.showHttpError(this.translate.get('error')['value'], message);
        this.refreshSearch();
      });
    });
  }

  disableRemoveAll() {
    return _.isEmpty(this.dataSource);
  }
  */

  ngOnInit() {
    // If the user changes the sort order, reset back to the first page.
    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);

    merge(this.sort.sortChange, this.paginator.page, this.search)
    .pipe(
      startWith({}),
      switchMap(() => {
        this.isLoadingResults = true;

        const params = {
          page: this.paginator.pageIndex ? this.paginator.pageIndex : 0,
          size: this.paginator.pageSize ? this.paginator.pageSize : this.pageSize
        };

        if (this.sort.active && this.sort.direction) {
          params['sort'] = this.sort.active + ',' + this.sort.direction
        }

        if (this.searchText) {
          params['name'] = this.searchText;
          return this.rest.getWithParams(this.url + '/search/name', params);
        } else {
          return this.rest.getWithParams(this.url, params);
        }
      }),
      map(data => {
        // Flip flag to show that loading has finished.
        this.isLoadingResults = false;
        this.resultsLength = data['page']['totalElements'];

        let number = this.paginator.pageIndex * this.paginator.pageSize;
        const items = data['_embedded']['institutions'];
        items.forEach(item => {
          item['number'] = ++number;
        });

        return items;
      }),
      catchError(() => {
        this.isLoadingResults = false;
        return observableOf([]);
      })
    // ).subscribe(data => this.dataSource = new MatTableDataSource<any>(data));
    ).subscribe(data => this.dataSource = data);
  }

  ngOnDestroy() {
  }

  /** Whether the number of selected elements matches the total number of rows. */
  /*
  isAllSelected() {
    const numSelected = this.selection.selected.length;
    const numRows = this.dataSource.data.length;
    return numSelected === numRows;
  }
  */

  /** Selects all rows if they are not all selected; otherwise clear selection. */
  /*
  masterToggle() {
    this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach(row => this.selection.select(row));
  }
  */
}
